package me.zhengjie.modules.weixin.rest;

import me.chanjar.weixin.mp.api.WxMpService;
import me.zhengjie.config.constant.WeChatConstant;
import me.zhengjie.config.utils.WechatUtil;
import me.zhengjie.modules.weixin.dto.WeChatAccount;
import me.zhengjie.modules.weixin.dto.WeChatPlatform;
import me.zhengjie.modules.weixin.enums.WechatConfigEnums;
import me.zhengjie.modules.weixin.handler.HandlerFactory;
import me.zhengjie.modules.weixin.service.IWechatEventService;
import me.zhengjie.modules.weixin.utils.WeChatMsgCrypt;
import me.zhengjie.modules.weixin.utils.WeChatUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信服务网关接口
 */
@RestController
@RequestMapping("wechat")
public class WeChatCgiController {
    private static final Logger log = LoggerFactory.getLogger(WeChatCgiController.class);

    @Autowired
    private HandlerFactory handler;

    @Autowired
    private WxMpService wxMpService;

    @Autowired
    private IWechatEventService wechatEventService;
    /**
     * 应用服务器和微信服务器的验证
     *
     * @param request
     * @throws IOException
     */
    @RequestMapping(value = "check", method = RequestMethod.GET)
    public void checkToken(HttpServletRequest request, HttpServletResponse response)
            throws Exception
    {
        // 根据channelId 获取token令牌信息
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        String[] array = {WechatConfigEnums.ATMR.getToken(), nonce, timestamp};
        Arrays.sort(array);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < array.length; i++)
        {
            sb.append(array[i]);
        }
        String jmStr = encodeSHA1(sb.toString()); // 得到加密后的字符串
        if (jmStr.equals(signature))
        {
            log.info("wechat token signature success");
            response.getWriter().print(echostr);
        }
        else
        {
            log.error("checkToken", "wechat token signature fail");
        }
    }

    /**
     * 接收微信服务器推送的消息
     *
     * @param request
     */
    @RequestMapping(value = "check", method = RequestMethod.POST)
    public void getRequestInfo(HttpServletRequest request, HttpServletResponse response)
    {
        try
        {
            // 获取微信推送来的信息
            Map<String, String> requestMsgMap = WechatUtil.reqMsgToMap(request);

            log.info("[接收微信推送的数据]=" + requestMsgMap.toString());
            // 获取返回给微信服务器的消息
            String responseData = wechatEventService.process(requestMsgMap);

            log.info("[返回给微信服务器的数据]=" + responseData);

            response.setContentType("application/xml;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(responseData);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    @RequestMapping(value = "wechat_bak/check")
    public String core(HttpServletRequest request) {

        String result = WeChatConstant.SUCCESS_FLAG;

        String signature = ServletRequestUtils.getStringParameter(request, WeChatConstant.SIGNATURE, "");
        String timestamp = ServletRequestUtils.getStringParameter(request, WeChatConstant.TIMESTAMP, "");
        String nonce = ServletRequestUtils.getStringParameter(request, WeChatConstant.NONCE, "");
        String echostr = ServletRequestUtils.getStringParameter(request, WeChatConstant.ECHOSTR, "");

        String platformAppId = request.getParameter(WeChatConstant.COMPONENTAPPID);

        Map<String, String> extraInfo = new HashMap<>(8);
        extraInfo.put(WeChatConstant.SIGNATURE, signature);
        extraInfo.put(WeChatConstant.TIMESTAMP, timestamp);
        extraInfo.put(WeChatConstant.NONCE, nonce);
        extraInfo.put(WeChatConstant.ECHOSTR, echostr);
        try {
            WeChatAccount account = new WeChatAccount(WechatConfigEnums.ATMR.getAppid());
            String signServer = WeChatUtil.INSTANCE.buildSignature(account.getToken(), nonce, timestamp);

            if (!wxMpService.checkSignature(timestamp,nonce,signature)){
                log.warn("签名校验不通过:"+signature+"-"+signServer);
                return WeChatConstant.FAIL_FLAG;
            }
            /*if (!signature.equals(signServer)) {
                log.warn("签名校验不通过:"+signature+"-"+signServer);
                return WeChatConstant.FAIL_FLAG;
            }*/
            // GET请求-首次接入验证； POST请求-除首次接入验证的其他所有请求
            if (RequestMethod.GET.name().equalsIgnoreCase(request.getMethod())) {
                return echostr;
            } else if (RequestMethod.POST.name().equalsIgnoreCase(request.getMethod())) {

                String postData = "";
                try {
                    postData = WeChatUtil.INSTANCE.convertInputStream2String(request.getInputStream());
                } catch (Exception e) {
                    return "Get Arguments Failed";
                }

                if (StringUtils.isBlank(postData)) {
                    log.error("postData is null:");
                    return WeChatConstant.FAIL_FLAG;
                }
                log.info("postData="+postData);
                String copyPostData = postData;
                String encryptType = ServletRequestUtils.getStringParameter(request, WeChatConstant.ENCRYPT_TYPE, "");
                String msgSignature = ServletRequestUtils.getStringParameter(request, WeChatConstant.MSG_SIGNATURE, "");

                WeChatMsgCrypt wxCrypt = null;

                if (StringUtils.isNotBlank(encryptType) && encryptType.equals(WeChatConstant.MSG_SIGN_TYPE_AES)) {
                    if (StringUtils.isBlank(msgSignature)) {
                        log.error("msgSignature is null:");
                        return WeChatConstant.FAIL_FLAG;
                    }

                    WeChatPlatform platform = account.getPlatform(platformAppId);
                    if (null == platform) {
                        log.error("platform is null:");
                        return WeChatConstant.FAIL_FLAG;
                    }

                    wxCrypt = new WeChatMsgCrypt(platform.getToken(), platform.getEncodingAESKey(), platform.getAppId());
                    copyPostData = wxCrypt.decryptMsg(msgSignature, timestamp, nonce, copyPostData);
                }
                extraInfo.put("postData", copyPostData);

                Map<String, Object> postMap = WeChatUtil.INSTANCE.convertXml2Map(copyPostData);

                result = handler.handle(account, postMap);

                extraInfo.put("respMsg", result);

                if (StringUtils.isNotBlank(encryptType) && encryptType.equals(WeChatConstant.MSG_SIGN_TYPE_AES)) {
                    if (null == wxCrypt) {
                        WeChatPlatform platform = account.getPlatform(platformAppId);
                        wxCrypt = new WeChatMsgCrypt(platform.getToken(), platform.getEncodingAESKey(), platform.getAppId());
                    }
                    result = wxCrypt.encryptMsg(result, timestamp, nonce);
                    extraInfo.put("respMsg", result);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * sha1 加密
     *
     * @param str
     * @return
     */
    public String encodeSHA1(String str)
    {
        try
        {
            StringBuffer sb = new StringBuffer();
            MessageDigest md = MessageDigest.getInstance("sha1");
            md.update(str.getBytes());
            byte[] msg = md.digest();
            for (byte b : msg)
            {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();

        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        return null;
    }

}
